package openvino

import (
	"fmt"
	"sync"
)

// Manager manages OpenVINO models and device selection
type Manager struct {
	models map[string]*Model
	mu     sync.RWMutex
}

// NewManager creates a new OpenVINO manager
func NewManager() *Manager {
	return &Manager{
		models: make(map[string]*Model),
	}
}

// LoadModel loads an OpenVINO model with the given configuration
func (m *Manager) LoadModel(modelID string, config ModelConfig) (*Model, error) {
	m.mu.Lock()
	defer m.mu.Unlock()

	// Check if model is already loaded
	if model, exists := m.models[modelID]; exists {
		return model, nil
	}

	// Load new model
	model, err := NewModel(config)
	if err != nil {
		return nil, fmt.Errorf("failed to load model %s: %w", modelID, err)
	}

	m.models[modelID] = model
	return model, nil
}

// GetModel retrieves a loaded model by ID
func (m *Manager) GetModel(modelID string) (*Model, error) {
	m.mu.RLock()
	defer m.mu.RUnlock()

	model, exists := m.models[modelID]
	if !exists {
		return nil, fmt.Errorf("model not found: %s", modelID)
	}

	return model, nil
}

// UnloadModel unloads a model by ID
func (m *Manager) UnloadModel(modelID string) error {
	m.mu.Lock()
	defer m.mu.Unlock()

	model, exists := m.models[modelID]
	if !exists {
		return fmt.Errorf("model not found: %s", modelID)
	}

	if err := model.Close(); err != nil {
		return fmt.Errorf("failed to close model %s: %w", modelID, err)
	}

	delete(m.models, modelID)
	return nil
}

// ListModels returns a list of loaded model IDs
func (m *Manager) ListModels() []string {
	m.mu.RLock()
	defer m.mu.RUnlock()

	ids := make([]string, 0, len(m.models))
	for id := range m.models {
		ids = append(ids, id)
	}

	return ids
}

// GetDeviceInfo returns information about available devices
func (m *Manager) GetDeviceInfo() ([]DeviceInfo, error) {
	return GetAvailableDevices()
}

// SelectDevice selects the best device for inference
func (m *Manager) SelectDevice(preferredDevice DeviceType) (DeviceType, error) {
	// If a specific device is requested, validate it
	if preferredDevice != "" && preferredDevice != DeviceAuto {
		if !preferredDevice.IsValid() {
			return "", fmt.Errorf("invalid device type: %s", preferredDevice)
		}
		return preferredDevice, nil
	}

	// Otherwise, use AUTO to let OpenVINO choose
	return DeviceAuto, nil
}

// Close closes all loaded models
func (m *Manager) Close() error {
	m.mu.Lock()
	defer m.mu.Unlock()

	var lastErr error
	for id, model := range m.models {
		if err := model.Close(); err != nil {
			lastErr = fmt.Errorf("failed to close model %s: %w", id, err)
		}
	}

	m.models = make(map[string]*Model)
	return lastErr
}

// GetModelCount returns the number of loaded models
func (m *Manager) GetModelCount() int {
	m.mu.RLock()
	defer m.mu.RUnlock()

	return len(m.models)
}

